//
//  thread.h
//  HelloCpp
//
//  Created by gww on 13-4-23.
//  Copyright (c) 2013年 Bullets in a Burning Box, Inc. All rights reserved.
//

#ifndef __MEDUSA_THREAD_H__
#define __MEDUSA_THREAD_H__

#include "../MedusaMacros.h"
#include "../atomic/atomic.h"
#include <string>
#include <pthread.h>

NS_MEDUSA_BEGIN

class Thread {
    
public:
    
    Thread() {
        ::pthread_attr_init(&this->attr);
        ::pthread_attr_setscope(&this->attr, PTHREAD_SCOPE_PROCESS);
        ::pthread_attr_setdetachstate(&this->attr, PTHREAD_CREATE_DETACHED);
    }
    
    virtual ~Thread() {
        ::pthread_attr_destroy(&this->attr);
    }
    
    bool IsRunning() const {
        return this->is_started.Get();
    }
    
    void Start() {
        
        if(!this->is_started.Get()) {
            ::pthread_create(&this->pid, &this->attr, Thread::thread_proc, this);
            this->is_started.Set(true);
        }
    }
    
    void Wait() const {
        void* status;
        ::pthread_join(this->pid, &status);
    }
    /*
    void Kill() const {
    }*/
    
protected:
    
    virtual void run() = 0;
    
private:
    
    static void* thread_proc(void* param) {
        Thread* self_ptr = static_cast<Thread*>(param);
        self_ptr->run();
        self_ptr->is_started.Set(false);
        
        return NULL;
    }
    
private:
    pthread_t pid;
    pthread_attr_t attr;
    AtomicBoolean is_started;
    
};

class LoopThread : public Thread {
    
public:
    
    LoopThread(int sleep_ms = 0) {
        this->is_running = false;
        this->sleep_ms = sleep_ms;
    }
    
    virtual ~LoopThread() {}
    
public:
    
    void Close() {
        this->is_running.Set(false);
    }
    
private:
    void run() {
        this->is_running.Set(true);
        while(this->is_running.Get()) {
            this->do_loop();
            if(this->sleep_ms >= 0)
                ::sleep(this->sleep_ms);
        }
    }
    
protected:
    
    virtual void do_loop() = 0;
    
private:
    
    AtomicBoolean is_running;
    int sleep_ms;
};

class MutexLock {
    
public:
    MutexLock() {
        ::pthread_mutex_init(&this->mutex,NULL);
    }
    
    ~MutexLock() {
        ::pthread_mutex_destroy(&this->mutex);
    }
    
    void Lock() {
        ::pthread_mutex_lock(&this->mutex);
    }
    
    void TryLock() {
        ::pthread_mutex_trylock(&this->mutex);
    }
    
    void Unlock() {
        ::pthread_mutex_unlock(&this->mutex);
    }
    
private:
    pthread_mutex_t mutex;
};
/*
 class SpinLock {
 
 public:
 SpinLock() {
 ::pthread_spin_init(&this->lock,NULL);
 
 }
 
 virtual ~SpinLock() {
 ::pthread_spin_destroy(&this->lock);
 }
 
 void Lock() {
 ::pthread_spin_lock(&this->lock);
 }
 
 void TryLock() {
 ::pthread_spin_trylock(&this->lock);
 }
 
 void Unlock() {
 ::pthread_spin_unlock(&this->lock);
 }
 
 private:
 pthread_spinlock_t lock;
 };*/


class ReadWriteLock {
    
public:
    
    ReadWriteLock() {
        ::pthread_rwlock_init(&this->lock,NULL);
    }
    
    ~ReadWriteLock() {
        ::pthread_rwlock_destroy(&this->lock);
    }
    
    void ReadLock() {
        ::pthread_rwlock_rdlock(&this->lock);
    }
    
    void WriteLock() {
        ::pthread_rwlock_wrlock(&this->lock);
    }
    
    void TryReadLock() {
        ::pthread_rwlock_tryrdlock(&this->lock);
    }
    
    void TryWriteLock() {
        ::pthread_rwlock_trywrlock(&this->lock);
    }
    
    void Unlock() {
        ::pthread_rwlock_unlock(&this->lock);
    }
    
private:
    pthread_rwlock_t lock;
};

/*
//#include <sys/semaphore.h>
#include <semaphore.h>
#include </usr/include/semaphore.h>
//#include <sem.h>

class SemVar {
    
public:
    
    SemVar() {
        ::sem_init(NULL,0);
    }
    
    virtual ~SemVar() {
        
    }
    
    void Post() {
        ::sem_post(NULL);
    }
    
    void Wait() {
        ::sem_post(&this->sem);
    }
    
    void TryWait() {
        ::sem_post(&this->sem);
    }
    
private:
    sem_t sem;
};

class CondVar {
    
public:
    
    CondVar() {
        pthread_cond_init(&mycond,NULL);
    }
    
    virtual ~CondVar() {
        pthread_cond_destroy(&mycond);
    }
    
private:
    pthread_cond_t mycond;
};*/

NS_MEDUSA_END

#endif
